package com.pan.lianjia;

import com.pan.crawler.HouseCrawler;
import com.pan.crawler.entity.HouseInfo;
import com.pan.lianjia.entity.LianJiaHouse;
import com.pan.utils.Sleep;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.edge.EdgeDriver;

import java.util.*;
import java.util.stream.Collectors;


public class LianJiaCrawlerImpl implements HouseCrawler {

    private EdgeDriver edgeDriver;

    private String url;

    public LianJiaCrawlerImpl(String url){
        this.url = url;
        edgeDriver = new EdgeDriver();
        edgeDriver.navigate().to(url);
        edgeDriver.manage().window().maximize();
        try {
            edgeDriver.findElement(By.className("mask-close")).click();
        }catch (Exception e){}

        WebElement areaUlElement = edgeDriver.findElement(By.xpath("//ul[@data-target='area' and @class='']"));
        List<WebElement> areaAList = areaUlElement.findElements(By.className("filter__item--level2"));
        this.items_size = areaAList.size();
        this.items_i = 6;
        areaAList.get(items_i).click();
        edgeDriver.findElement(By.xpath("//li[@data-id='200600000001']")).click();
    }

    enum LocatorEnum{
        CLASS,
        ID,
        CSS_SELECT
    }

    public enum HouseType{
        No_Apartment(0),
        Apartment(1);
        int type;
        HouseType(int type) {
            this.type = type;
        }
        public int getType() {
            return type;
        }
    }
    private boolean hasDom(LocatorEnum locatorEnum,String targetName){
        return this.hasDom(locatorEnum,edgeDriver.findElement(By.cssSelector("body")),targetName);
    }
    private  boolean hasDomByClass(WebElement webElement,String targetName){
        return this.hasDom(LocatorEnum.CLASS,webElement,targetName);
    }
    private boolean hasDom(LocatorEnum locatorEnum, WebElement webElement,String targetName){
        By by = null;
        if (locatorEnum.equals(LocatorEnum.CLASS)){
            by = By.className(targetName);
        }else if (locatorEnum.equals(LocatorEnum.ID)){
            by = By.id(targetName);
        }else if (locatorEnum.equals(LocatorEnum.CSS_SELECT)){
            by = By.cssSelector(targetName);
        }
        try {
            webElement.findElement(by);
            return true;
        }catch (Exception e){}
        return false;
    }

    private int items_i ;
    private int items_size;
    @Override
    public String nextItem() {
        int isNextArea = 0;
        if (hasNxtPriceItem()){
            nextPriceItem();
        }else {
            WebElement areaUlElement = edgeDriver.findElement(By.xpath("//ul[@data-target='area' and @class='']"));
            List<WebElement> areaAList = areaUlElement.findElements(By.className("filter__item--level2"));
            areaAList.get(items_i++).click();
            isNextArea++;
            houseSet.clear();
        }
        return String.valueOf(items_i-isNextArea);
    }
    private int getItemHouseSize() {
        String text = edgeDriver.findElement(By.className("content__title--hl")).getText();
        return Integer.parseInt(text);
    }

    /**
     * 注意：链家的价格筛选是左右闭区间的
     */
    private int item_price = 0;
    public void nextPriceItem(int... addValue){
        Sleep.sleep();
        int add  = 1000;
        if (addValue.length > 0){
            add = addValue[0];
        }
        WebElement inputStart = edgeDriver.findElement(By.xpath("//input[@data-el='input_start']"));
        WebElement inputEnd = edgeDriver.findElement(By.xpath("//input[@data-el='input_end']"));
        inputStart.clear();
        inputEnd.clear();
        inputStart.sendKeys(String.valueOf(item_price+1));
        if (add == -1){
            inputEnd.sendKeys("");
        }else {
            inputEnd.sendKeys(String.valueOf(item_price+add));
        }
        WebElement button = edgeDriver.findElement(By.xpath("//span[@data-el='button' and @class='filter__button']"));
        button.click();
        int itemHouseSize = getItemHouseSize();
        if (itemHouseSize>3000){
            nextPriceItem(add/10);
        }
        else if (itemHouseSize<=3000 && itemHouseSize>0) {
            item_price += add;
        }
        else if (itemHouseSize==0) {
            if (add<10000 && add > 0) {
                nextPriceItem(add * 2);
            } else if (add>=10000) {
                nextPriceItem(-1);
            } else if (add == -1) {
                item_price = 0;
            }
        }
    }
    public boolean hasNxtPriceItem(){
        WebElement inputStart = edgeDriver.findElement(By.xpath("//input[@data-el='input_start']"));
        WebElement inputEnd = edgeDriver.findElement(By.xpath("//input[@data-el='input_end']"));
        String startValue = inputStart.getAttribute("value");
        String endValue = inputEnd.getAttribute("value");
        if ( endValue.length() == 0  && startValue.length() > 0) {
            return false;
        }else {
            return true;
        }
    }
    @Override
    public boolean hasNxtItem() {
        if (items_i==items_size) {
            return hasNxtPriceItem();
        }
        return true;
    }

    @Override
    public HashMap<Integer, List<HouseInfo>> getPageHouse(){
        HashMap<Integer,List<HouseInfo>> map = new HashMap<>();
        List<HouseInfo> gLi = new ArrayList<>();
        List<HouseInfo> zLi = new ArrayList<>();
        map.put(HouseType.No_Apartment.getType(),zLi);
        map.put(HouseType.Apartment.getType(), gLi);
        int titleSize = edgeDriver.findElements(By.className("content__title")).size();
        List<WebElement> houseElements = null;
        if (titleSize==1){
            houseElements = edgeDriver.findElements(By.className("content__list--item--main"));
        } else if (titleSize == 2) {
            houseElements = edgeDriver.findElement(By.className("content__list")).findElements(By.className("content__list--item--main"));
        }
        if (houseElements.size()==0){
            Sleep.sleep();
            edgeDriver.navigate().refresh();
            houseElements = edgeDriver.findElements(By.className("content__list--item--main"));
        }
        houseElements.forEach(houseElement-> addHouseInfo(houseElement,map));
        return map;
    }

    private HashSet<String> houseSet = new HashSet<>();
    private void addHouseInfo(WebElement webElement,HashMap<Integer,List<HouseInfo>> map){
        LianJiaHouse lianJiaHouse = new LianJiaHouse();
        WebElement titleAElement = webElement.findElement(By.className("content__list--item--title")).findElement(By.cssSelector("a"));
        String title = titleAElement.getText();
        String url = titleAElement.getAttribute("href");
        WebElement houseTagsElement = webElement.findElement(By.className("content__list--item--des"));
        String houseTags = houseTagsElement.getText();
        WebElement orderTagsElement = webElement.findElement(By.className("content__list--item--bottom"));
        String orderTags = orderTagsElement.getText();
        WebElement priceElement = webElement.findElement(By.className("content__list--item-price"));
        String price = priceElement.findElement(By.cssSelector("em")).getText();
        String area = "";
        String houseType = "";
        String[] tagArr = houseTags.split("/");
        for (String tag : tagArr){
            if (tag.indexOf("㎡") > -1){
                area = tag;
            } else if (tag.indexOf("厅") > -1) {
                houseType = tag;
            }
        }
        if (price.indexOf("-") != -1) {
            WebElement parentElement = webElement.findElement(By.xpath(".."));
            String houseCode = parentElement.getAttribute("data-house_code");
            if (houseSet.contains(houseCode)) return;
            houseSet.add(houseCode);
        }
        lianJiaHouse.setTitle(title).setUrl(url)
                .setHouseTags(houseTags).setArea(area)
                .setHouseType(houseType).setOrderTags(orderTags)
                .setPrice(price);
        String address = "";
        boolean isG = hasDomByClass(webElement,"content__item__tag--authorization_apartment");
        if (isG){
            lianJiaHouse.setAddress(address);
            map.get(HouseType.Apartment.getType()).add(lianJiaHouse);
        }else {
            address = tagArr[0];
            lianJiaHouse.setAddress(address);
            map.get(HouseType.No_Apartment.getType()).add(lianJiaHouse);
        }
        return ;
    }

    @Override
    public String nextPage() {
        WebElement next = edgeDriver.findElement(By.className("next"));
        String href = next.getAttribute("href");
        try {
            next.click();
        }catch (Exception e){
            if (hasDom(LocatorEnum.CLASS,"guarantee-close")){
                edgeDriver.findElement(By.className("guarantee-close")).click();
            }
            next.click();
        }
        if (Math.random()<0){
            System.out.println("打开网页");
            Sleep.sleep(3000);
            WebElement houseElement  = edgeDriver.findElement(By.xpath("//div[@data-el='listItem']"));
            houseElement.findElement(By.cssSelector("a")).click();
            Sleep.sleep();
            if (edgeDriver.getWindowHandles().size()>1){
                edgeDriver.switchTo().window(edgeDriver.getWindowHandles().stream().reduce((a,b)->b).get());
                try {
                    edgeDriver.close();
                }catch (Exception e){
                    edgeDriver.navigate().refresh();
                    edgeDriver.close();
                }
                edgeDriver.switchTo().window(edgeDriver.getWindowHandles().stream().findFirst().get());
            }
        }
        return href;
    }

    @Override
    public boolean hasNxtPage() {
        if (!hasDom(LocatorEnum.CLASS, "next")){
            Sleep.sleep();
            edgeDriver.navigate().refresh();
            return hasDom(LocatorEnum.CLASS, "next");
        } else {
            return true;
        }
    }
    @Override
    public void close() {
        edgeDriver.quit();
    }
}
